/*
 * Copyright 2002-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package config;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.web.AuthenticationEntryPoint;

//The @EnableResourceServer annotation adds a filter of type OAuth2AuthenticationProcessingFilter
//automatically to the Spring Security filter chain.


/*
tokenServices: the bean that defines the token services (instance of ResourceServerTokenServices).
used DefaultTokenServices 

resourceId: the id for the resource (optional, but recommended and will be validated by the auth server if present).

other extension points for the resourecs server (e.g. tokenExtractor for extracting the tokens from incoming requests)
request matchers for protected resources (defaults to all)
access rules for protected resources (defaults to plain "authenticated")
other customizations for the protected resources permitted by the HttpSecurity configurer in Spring Security
*/	

@Configuration
public class OAuth2ServerConfig {

	@Configuration
	@EnableResourceServer
	protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
	
		@Override
		public void configure(HttpSecurity http) throws Exception {
			http.csrf().disable()
			.anonymous().disable()
			.requestMatchers().antMatchers("/user*/**")
			.and().authorizeRequests()
			.antMatchers("/user*/**").permitAll();
		}
	}
	
//	---------------------------------authorize---------------------------------------------------------
	@Configuration
	@EnableAuthorizationServer								
	protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

		@Autowired
		private TokenStore tokenStore;	//token存储 backend storage or local encoding
		/*@Autowired
		private UserApprovalHandler userApprovalHandler;*/

		@Autowired
		@Qualifier("authenticationManagerBean")
		private AuthenticationManager authenticationManager;

		@Override
		public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
			clients.inMemory()
					.withClient("demo")	//
					.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
		            .authorities("ROLE_USER", "ROLE_TRUSTED_CLIENT")
		            .scopes("read", "write", "trust")//授权用户的操作权限
		            .secret("secret")//密码
					.accessTokenValiditySeconds(6000);//token有效期为120秒
		}
		@Bean
		public TokenStore tokenStore() {
			return new InMemoryTokenStore();	//存储到内存
		}
		//(token services)
		@Override
		public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		/*	endpoints.tokenStore(tokenStore)
		  			.userApprovalHandler(userApprovalHandler)	//a simple yes/no decision via user_oauth_approval equals to "true" or "false".
					.authenticationManager(authenticationManager);*/
			endpoints.tokenStore(tokenStore)	
					.authenticationManager(authenticationManager);//密码准许开关，开启后可以使用password方式获取accessToken
		}
		//定义令牌端点的安全约束
		@Override
		public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
			oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").realm("myWeb");
		}

	}

}
